class MyPromise {
  state = 'pending'; // promise 的三种状态pending、fulfilled、rejected
  value = undefined; // 成功的值
  reason = undefined; // 失败的原因

  resolveCallbacks = []; // pending状态下，存储成功的回调
  rejectCallbacks = []; // pending状态下，存储失败的回调

  constructor(fn) {
    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.resolveCallbacks.forEach((fn) => fn(this.value));
      }
    };
    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.rejectCallbacks.forEach((fn) => fn(this.reason));
      }
    };

    try {
      fn(resolveHandler, rejectHandler);
    } catch (error) {
      rejectHandler(error);
    }
  }

  then(fn1, fn2) {
    fn1 = typeof fn1 === 'function' ? fn1 : (v) => v;
    fn2 = typeof fn2 === 'function' ? fn2 : (err) => err;

    if (this.state === 'pending') {
      const p = new MyPromise((resolve, reject) => {
        this.resolveCallbacks.push(() => {
          try {
            const newValue = fn1(this.value);
            resolve(newValue);
          } catch (error) {
            reject(error);
          }
        });

        this.rejectCallbacks.push(() => {
          try {
            const newReason = fn2(this.reason);
            reject(newReason);
          } catch (error) {
            reject(error);
          }
        });
      });

      return p;
    }

    if (this.state === 'fulfilled') {
      const p = new MyPromise((resolve, reject) => {
        try {
          const newValue = fn1(this.value);
          resolve(newValue);
        } catch (error) {
          reject(error);
        }
      });

      return p;
    }

    if (this.state === 'rejected') {
      const p = new MyPromise((resolve, reject) => {
        try {
          const newReason = fn2(this.reason);
          reject(newReason);
        } catch (error) {
          reject(error);
        }
      });

      return p;
    }
  }

  catch(fn) {
    return this.then(null, fn);
  }
}

MyPromise.resolve = function (value) {
  return new MyPromise((resolve, reject) => {
    resolve(value);
  });
};

MyPromise.reject = function (reason) {
  return new MyPromise((resolve, reject) => {
    reject(reason);
  });
};

MyPromise.all = function (promiseList) {
  const p = new MyPromise((resolve, reject) => {
    const result = [];
    const length = promiseList.length;
    let resolvedCount = 0;

    promiseList.forEach((pItem) => {
      pItem
        .then((data) => {
          result.push(data);
          resolvedCount++;

          if (resolvedCount === length) {
            resolve(result);
          }
        })
        .catch((error) => {
          reject(error);
        });
    });
  });

  return p;
};

MyPromise.race = function (promiseList) {
  const p = new MyPromise((resolve, reject) => {
    const isResolved = false;

    promiseList.forEach((pItem) => {
      pItem
        .then((data) => {
          if (!isResolved) {
            resolve(data);
            isResolved = true;
          }
        })
        .catch((err) => reject(err));
    });
  });
  return p;
};
